from typing import List, Dict
import pandas as pd
import feffery_antd_components as fac
from dash import callback, Output, Input, State, dcc, html, MATCH, ctx, no_update


class DFTable:
    instance_store = {}  # 用于存储实例

    def __init__(
        self,
        df: pd.DataFrame,
        name: str,
        columns: List[str] = None,
        sortable_cols=None,
        page_size=10,
        downloadable=False,
        mode="client-side",
    ):
        self.df = df
        self.name = name
        self.columns = columns
        self.sortable_cols = sortable_cols
        self.page_size = page_size
        self.downloadable = downloadable
        self.mode = mode
        # 将实例存入类变量
        DFTable.instance_store[name] = self

    @property
    def layout(self):
        components = []

        df_cols = self.df.columns
        if self.columns:
            df_cols = df_cols.intersection(self.columns)
        cols = [
            {
                "title": c,
                "dataIndex": c,
            }
            for c in df_cols
        ]
        if self.mode == "client-side":
            data = self.df[df_cols].to_dict("records")
        elif self.mode == "server-side":
            data = self.df[df_cols].iloc[: self.page_size].to_dict("records")
        table = fac.AntdTable(
            id={"type": "df-table", "index": self.name},
            columns=cols,
            data=data,
            mode=self.mode,
            pagination={
                "total": self.df.shape[0],
                "current": 1,
                "pageSize": self.page_size,
                "showSizeChanger": True,
                "pageSizeOptions": [
                    self.page_size,
                    self.page_size * 2,
                    self.page_size * 4,
                    self.page_size * 10,
                ],
                "position": "bottomRight",
                "showQuickJumper": True,
            },
        )

        components.append(table)

        if self.downloadable:
            components.append(
                fac.AntdButton(
                    "下载数据",
                    id={"type": "df-table-download-button", "index": self.name},
                )
            )
            components.append(
                dcc.Download(id={"type": "df-table-download", "index": self.name})
            )

        return html.Div(components)


@callback(
    Output({"type": "df-table-download", "index": MATCH}, "data"),
    Input({"type": "df-table-download-button", "index": MATCH}, "nClicks"),
    State({"type": "df-table", "index": MATCH}, "data"),
)
def download_data(nClicks, data):
    if nClicks:
        id = ctx.triggered_id["index"]
        df = pd.DataFrame(data)
        return dcc.send_data_frame(df.to_excel, f"{id}.xlsx")


@callback(
    Output({"type": "df-table", "index": MATCH}, "data"),
    Input({"type": "df-table", "index": MATCH}, "pagination"),
    prevent_initial_call=True,
)
def server_side_pagination_data(pagination):
    if pagination:
        table_instance: DFTable = DFTable.instance_store[ctx.triggered_id["index"]]
        if table_instance.mode == "server-side":
            df = table_instance.df  # 获取对应的 DataFrame

            # 根据当前分页的current参数、pageSize参数，从df中抽取对应数据帧
            data_frame = df.iloc[
                (pagination["current"] - 1)
                * pagination["pageSize"] : pagination["current"]
                * pagination["pageSize"],
                :,
            ]

            # time.sleep(0.5)  # 渲染加载动画更好看 ^_^
            return data_frame.to_dict("records")

    return no_update
